<?php
declare (strict_types = 1);

namespace app\command\logic;

use app\command\logic\BaseLogic;

/**
 * php think mq:consumer member_oplog
 * 用户api请求统计数据 逆地理编码
 */
class ConsumerLogicApiLog extends BaseLogic implements ConsumerInterface
{

    /**
     * 消费者执行入口方法
     * {@inheritdoc}
     */
    public function run(array $msg): bool
    {
        $tag        = '';
        $msg['api'] = str_replace('//', '/', $msg['api']);
        if ($msg['api'] == '/api/goods/goodsDetail') {
            $params = json_decode($msg['params'], true);
            // {"goodsId":"13"}
            $goodsId = $params['goodsId'] ?? 0;
            if ($goodsId > 0) {
                // `goods_type '1线下 2线上',
                $goods = \think\facade\Db::table('goods')
                    ->field(['goods_type', 'shop_id'])
                    ->where('id', $goodsId)
                    ->find();
                $goods_type = $goods['goods_type'] ?? 0;
                if ($goods_type == 1) {
                    $tag = 'offline';
                } elseif ($goods_type == 2) {
                    $tag = 'online';
                }
                $shopId = $goods['shop_id'] ?? 0;

                $params['stats'] = '_shop_' . $shopId . '_shop_';
                $msg['params']   = json_encode($params, 320);
            }
        } elseif (strpos($msg['api'], '/api/shop/shopDetail') === 0) {
            $params = json_decode($msg['params'], true);
            if (empty($params)) {
                $params = [];
            }
            $shopId          = $params['shopId'] ?? 0;
            $params['stats'] = '_shop_' . $shopId . '_shop_';
            $msg['params']   = json_encode($params, 320);
        }
        $data = [
            'user_id'     => $msg['user_id'],
            'create_at'   => $msg['create_at'],
            'geoip'       => $msg['geoip'],
            'lng'         => $msg['lng'], // longitude 经度
            'lat'         => $msg['lat'], // latitude 纬度
            'trace_id'    => $msg['trace_id'],
            'device_type' => $msg['device_type'],
            'device_id'   => substr((string) $msg['device_id'], 0, 80),
            'referer'     => substr((string) $msg['referer'], 0, 255),
            'api'         => substr((string) $msg['api'], 0, 200),
            'tag'         => $tag,
            'method'      => $msg['method'],
            'params'      => $msg['params'],
            'duration'    => $msg['duration'], // 0.019958019256592
            'op_result'   => substr((string) $msg['op_result'], 0, 1000),
            'useragent'   => substr((string) $msg['useragent'], 0, 1000),
        ];
        // 插入日志到数据库
        \think\facade\Db::name('member_oplog')->insert($data);

        if ( ! empty($msg['lng']) && ! empty($msg['lat'])) {
            $where = [
                'user_id' => $msg['user_id'],
                'lng'     => $msg['lng'],
                'lat'     => $msg['lat'],
            ];
            $count = \think\facade\Db::name('member_reverse_geocoding')
                ->where($where)
                ->count();
            if ($count > 0) {
                \think\facade\Db::name('member_reverse_geocoding')
                    ->where($where)
                    ->inc('count', 1)
                    ->update([
                        'update_at' => $msg['create_at'],
                    ]);
            } else {
                $res = $this->reverseGeocoding(
                    $msg['lng'],
                    $msg['lat']
                );

                $data2 = [
                    'create_at'             => $msg['create_at'],
                    'user_id'               => $msg['user_id'],
                    'lng'                   => $msg['lng'],
                    'lat'                   => $msg['lat'],

                    'formatted_address_poi' => is_string($res['formatted_address_poi']) ? $res['formatted_address_poi'] : json_encode($res['formatted_address_poi'], 320),
                    'edz'                   => json_encode($res['edz'], 320),
                    'formatted_address'     => $res['formatted_address'],
                    'business'              => $res['business'],
                    'sematic_description'   => $res['sematic_description'],
                    'country'               => $res['addressComponent']['country'],
                    'country_code'          => $res['addressComponent']['country_code'],
                    'country_code_iso'      => $res['addressComponent']['country_code_iso'],
                    'country_code_iso2'     => $res['addressComponent']['country_code_iso2'],
                    'province'              => $res['addressComponent']['province'],
                    'city'                  => $res['addressComponent']['city'],
                    'city_level'            => $res['addressComponent']['city_level'],
                    'district'              => $res['addressComponent']['district'],
                    'town'                  => $res['addressComponent']['town'],
                    'town_code'             => $res['addressComponent']['town_code'],
                    'distance'              => $res['addressComponent']['distance'],
                    'direction'             => $res['addressComponent']['direction'],
                    'adcode'                => $res['addressComponent']['adcode'],
                    'street'                => $res['addressComponent']['street'],
                    'street_number'         => $res['addressComponent']['street_number'],
                    'count'                 => 1,
                ];
                \think\facade\Db::name('member_reverse_geocoding')
                    ->insert($data2);
            } // 示例：返回一个布尔值
            return true;
        }
        return true;
    }

    /**
     * 全球逆地理编码
     *
     * https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-geocoding-abroad-base#服务状态码
     * @param  string $lng  longitude 经度
     * @param  string $lat  latitude 纬度
     * @return [type]      [description]
     */
    private function reverseGeocoding($lng, $lat)
    {
        // $lng = '113.7225';
        // $lat = '34.7724';
        $ak = env('baidumap.ak');
        $sk = env('baidumap.sk');

        // 百度地图逆地理编码API URL
        $uri = '/reverse_geocoding/v3/';

        // 需要转换的经纬度坐标，格式为"lat,lon"
        $location   = sprintf('%s,%s', $lat, $lng);
        $coordstype = "gcj02ll"; // 坐标类型，gcj02ll 表示国测局经纬度坐标
        // 请求参数数组
        $params = [
            'location'        => $location,
            'coordstype'      => $coordstype,
            'ak'              => $ak,
            'extensions_town' => true,
            'extensions_poi'  => 1,
            'output'          => 'json',
        ];

        // 计算签名
        $sn = $this->caculateAKSN($ak, $sk, $uri, $params);

        // 构造最终请求URL，包括签名
        $requestUrl = sprintf(
            "https://api.map.baidu.com%s?%s",
            $uri,
            http_build_query(array_merge($params, ['sn' => $sn]))
        );

        // 发送HTTP GET请求
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $requestUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);
        // 解码响应内容
        $result = json_decode($response, true);

        if ($result['status'] == 0) {
            /*
                {
                    "status": 0,
                    "result":
                    {
                        "location":
                        {
                            "lng": 113.72249999999994,
                            "lat": 34.7723999698049
                        },
                        "formatted_address": "河南省郑州市金水区黑朱庄路",
                        "edz":
                        {
                            "name": "郑东新区"
                        },
                        "business": "金水路,民航路,未来路",
                        "addressComponent":
                        {
                            "country": "中国",
                            "country_code": 0,
                            "country_code_iso": "CHN",
                            "country_code_iso2": "CN",
                            "province": "河南省",
                            "city": "郑州市",
                            "city_level": 2,
                            "district": "金水区",
                            "town": "未来路街道",
                            "town_code": "410105012",
                            "distance": "",
                            "direction": "",
                            "adcode": "410105",
                            "street": "黑朱庄路",
                            "street_number": ""
                        },
                        "pois":
                        [],
                        "roads":
                        [],
                        "poiRegions":
                        [],
                        "sematic_description": "",
                        "formatted_address_poi": "",
                        "cityCode": 268
                    }
                }
         */
            return $result['result'];
        }
        return $result['message'];
    }

    private function caculateAKSN($ak, $sk, $url, $params, $method = 'GET')
    {
        if ($method === 'POST') {
            ksort($params);
        }
        $querystring = http_build_query($params);
        return md5(urlencode($url . '?' . $querystring . $sk));
    }
}
